#ifndef xpack_interface_ranger
#define xpack_interface_ranger
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::interface_ranger::inc
#include"adapter/random_access.hpp"
#include"define/base_type.hpp"
#include"define/classify.hpp"
#include"interface/initializer_list.hpp"
#include"interface/seqptr.hpp"
#include"macro/xalign.hpp"
#include"macro/xexport.hpp"
#include"macro/xmodify.hpp"
#include"macro/xstruct.hpp"
#include"meta/has_cast.hpp"
#include"meta/has_operator_cast.hpp"
#include"math/index_system.hpp"
#include"meta/is_origin_arrayx.hpp"
#include"meta/is_origin_stringx.hpp"
#include"meta/is_the_xstruct.hpp"
#include"meta/item_of.hpp"
#include"meta/item_origin_of.hpp"
#include"meta/remove_ref.hpp"
#pragma pop_macro("xuser") 

namespace mixc::interface_ranger{
    using namespace inc;

    template<class seq_t>
    concept has_length = requires(seq_t seq, uxx length){
        length  = seq->length;
    };

    template<class seq_t, class item_t>
    concept has_ptr_length_pairx = 
        has_length<seq_t> and (inc::has_cast<item_t *, seq_t> or inc::has_operator_cast<item_t *, seq_t>);

    template<class seq_t, class item_t>
    concept has_indexer_length_pairx = requires(seq_t seq, item_t * ptr, uxx length){
        // 为了兼容 msvc 16.8 以下版本：使用 seq.operator item_t & []() 会出现编译器内部错误
        ptr     = & seq[uxx(0)];
        length  = seq->length;
    };

    template<class seq_t>
    concept has_indexer_length_pair = 
        has_indexer_length_pairx<seq_t, inc::item_origin_of<seq_t>>;

    template<class object_t>
    struct helper{
        // 为了兼容 msvc 16.8 以下版本：全局静态内联模板变量对齐无效的 bug，只能套个结构体曲线救国
        static inline xalign(sizeof(voidp) * 2) voidp itrs[2];
    };

    template<class item_t>
    xstruct(
        xname(ranger_base),
        xprof(m_ptr, voidp  ),
        xprof(m_itr, voidp *),
        xprof(m_len, uxx    ),
        xprof(m_ofs, uxx    )
    )
    public:
        xprops()
            xpubgetx(is_positive_order, bool){
                xr { return (uxx(xthe.m_itr) & mask) == 0; }
            };

            xpubgetx(is_negtive_order, bool){
                xr{ return (uxx(xthe.m_itr) & mask) != 0; }
            };

            xpubgetx(length, uxx){
                xr{ return xthe.m_len; }
            };

            xpubgetx(is_support_logic_inverse, bool){
                xr{ return true; }
            };
        $

        xprops_operator()

    private:
        enum{ mask  = sizeof(voidp) * 2 - 1 };

        template<class object, class return_type>
        static return_type & pos(ranger_base * this_ptr, uxx index){
            return (*(object *)this_ptr->m_ptr)[this_ptr->m_ofs + index];
        }

        template<class object, class return_type>
        static return_type & neg(ranger_base * this_ptr, uxx index){
            return (*(object *)this_ptr->m_ptr)[this_ptr->m_ofs - index];
        }

        template<class return_type>
        static return_type & posx(ranger_base * this_ptr, uxx index){
            return ((return_type *)this_ptr->m_ptr)[this_ptr->m_ofs + index];
        }

        template<class return_type>
        static return_type & negx(ranger_base * this_ptr, uxx index){
            return ((return_type *)this_ptr->m_ptr)[this_ptr->m_ofs - index];
        }

    protected:
        void turn_positive_order() {
            m_itr = (voidp *)(uxx(m_itr) & ~mask);
        }

        void turn_negtive_order() {
            m_itr = (voidp *)(uxx(m_itr) | sizeof(uxx));
        }

        item_t & access(uxx index) const {
            using invoke_t = item_t &(*)(ranger_base const *, uxx);
            return invoke_t(*m_itr)(this, index);
        }

    private:
        template<class object_t>
        void init(object_t const * ptr, uxx len){
            this->m_ptr     = (object_t *)ptr;
            this->m_itr     = (voidp *)helper<object_t>::itrs;
            this->m_len     = (uxx)len;
            this->m_ofs     = (0);
        }

    public:
        ranger_base(item_t * seq, uxx len){
            init(seq, len);
            m_itr[0]        = voidp(& posx<item_t>);
            m_itr[1]        = voidp(& negx<item_t>);
        }

        template<class seq_t>
        ranger_base(seq_t const & seq){
            init(xmodify(seq), seq->length);
            m_itr[0]        = voidp(& pos<seq_t, item_t>);
            m_itr[1]        = voidp(& neg<seq_t, item_t>);
        }
    $

    template<class item_type>
    xstruct(
        xtmpl(ranger, item_type),
        xpubb(ranger_base<item_type>),
        xpubb(inc::random_access<ranger<item_type>, item_type>),
        xwhos(inc::classify_t::interface_ranger)
    )
    public:
        using item_t    = item_type;
        using final_t   = the_t;

        constexpr ranger():
            ranger(nullptr, 0){
        }

        template<class seq_t>
        requires(
            inc::is_origin_arrayx<seq_t, item_t> and not inc::is_origin_stringx<seq_t, item_t>
        )
        constexpr ranger(seq_t && ary) : 
            ranger(ary, sizeof(seq_t) / sizeof(ary[0])){}

        template<class seq_t>
        requires(inc::is_origin_stringx<seq_t, item_t>)
        constexpr ranger(seq_t && list) : 
            ranger(list, ([&](){
                uxx i = 0;
                while(list[i] != '\0'){
                    i++;
                }
                return i;
            })()){
        }

        constexpr ranger(item_t const * ptr, uxx len) :
            ranger_base<item_t>((item_t *)ptr, len){}

        constexpr ranger(inc::initializer_list<item_t> const & seq) :
            ranger(seq.begin(), seq.size()){
        }

        constexpr ranger(inc::seqptr<item_t> const & seq) :
            ranger(seq, seq->length){
        }

        template<class seq_t>
        requires(
            has_indexer_length_pairx<seq_t, item_t> and
            has_ptr_length_pairx<seq_t, item_t> == false
        )
        constexpr ranger(seq_t const & seq) : ranger_base<item_t>(seq){}

        template<class seq_t>
        requires(
            has_indexer_length_pairx<seq_t, item_t> and
            has_ptr_length_pairx<seq_t, item_t> == false
        )
        constexpr ranger(seq_t const & seq, uxx length) :
            ranger_base<item_t>(seq){
            ranger_base<item_t>::m_len = length;
        }

        template<class seq_t>
        requires(has_ptr_length_pairx<seq_t, item_t>)
        constexpr ranger(seq_t const & list, uxx length) : 
            ranger_base<item_t>((item_t *)(seq_t &)list, length){
        }

        template<class seq_t>
        requires(has_ptr_length_pairx<seq_t, item_t>)
        constexpr ranger(seq_t const & list) : 
            ranger_base<item_t>((item_t *)(seq_t &)list, list->length){
        }

        final_t backward(uxx offset) const {
            if (the_t r = xthe; xthe->is_positive_order){
                r.m_ofs += offset;
                r.m_len -= offset;
                return r;
            }
            else{
                r.m_ofs -= offset;
                r.m_len -= offset;
                return r;
            }
        }

        final_t forward(uxx offset) const {
            return backward(uxx(0) - offset);
        }

        template<can_interval interval_t>
        final_t subseq(interval_t const & i) const {
            final_t r       = xthe;
            uxx plus        = i.normalize(xthe->length) == bstate_t::fail ? 0 : 1;

            if (xthe->is_positive_order){ // 正序
                if (i->left <= i->right){ // 正序
                    r.m_ofs += i->left;
                    r.m_len  = i->right - i->left + plus;
                }
                else{ // 反序
                    r.m_ofs += i->left;
                    r.m_len  = i->left - i->right + plus;
                    r.turn_negtive_order();
                }
            }
            else{ // 反序
                if (i->left <= i->right){ // 反序 & 正序 -> 反序
                    r.m_ofs -= i->left;
                    r.m_len  = i->right - i->left + plus;
                }
                else{ // 反序 & 反序 -> 正序
                    r.m_ofs -= i->left;
                    r.m_len  = i->left - i->right + plus;
                    r.turn_positive_order();
                }
            }
            return r;
        }

    private:
        friend inc::random_access<the_t, item_type>;

        item_t & random_get(uxx index) const {
            return ranger_base<item_t>::access(index);
        }
    $

    template<class seq_t, class item_t>
    concept can_rangerlizex = requires(seq_t && seq){
        ranger<item_t>(seq);
    };

    template<class seq_t>
    concept can_rangerlize = 
        can_rangerlizex<
            seq_t, 

            // 不能是 inc::item_origin_of<seq_t> 比如元素类型是 asciis 就会移除 const 标记
            inc::remove_ref<inc::item_of<seq_t>>
        >;
}

namespace mixc::interface_ranger::origin{
    using mixc::interface_ranger::can_rangerlize;
    using mixc::interface_ranger::can_rangerlizex;
    using mixc::interface_ranger::ranger;
}

#endif

xexport_space(mixc::interface_ranger::origin)